/**
 *    Copyright (C) 2008, 2009  Victor Smirnov <aist11@gmail.com>
 *
 *    This program is free software; you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation; either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License along
 *    with this program; if not, write to the Free Software Foundation, Inc.,
 *    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *    See LICENSE.exceptions in the root folder of this project for possible
 *    exceptions
 *
 */

#ifndef _CUBEFS_CORE_API_MODELS_LOGS_HPP
#define	_CUBEFS_CORE_API_MODELS_LOGS_HPP

#include <cubefs/api/models/logs.hpp>
#include <cubefs/core/api/reflection/type.hpp>

namespace cubefs    {
namespace api       {

template <typename Interface>
class LogHandlerImplT: public TypedImplT<Interface> {
	typedef LogHandlerImplT<Interface>		Me;
	typedef TypedImplT<Interface>			Base;
public:

    virtual void begin(Int level)       = 0;

    virtual void log(bool value)        = 0;
    virtual void log(Byte value)        = 0;
    virtual void log(UByte value)       = 0;
    virtual void log(Short value)       = 0;
    virtual void log(UShort value)      = 0;
    virtual void log(Int value)         = 0;
    virtual void log(UInt value)        = 0;
    virtual void log(BigInt value)      = 0;
    virtual void log(float value)       = 0;
    virtual void log(double value)      = 0;
    virtual void log(IDValue value)     = 0;
    virtual void log(StringRef value)   = 0;
    virtual void log(const char* value) = 0;
    virtual void log(const void* value) = 0;

    virtual void end()                  = 0;

    virtual bool managed() const {
        return false;
    }

    static void Init() {
        AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
        type_ = type;
    }


    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* LogHandlerImplT<Interface>::type_		= NULL;
typedef LogHandlerImplT<LogHandler>			LogHandlerImpl;



template <typename Interface>
class DefaultLogHandlerImplT: public LogHandlerImplT<Interface> {
public:
    virtual void begin(Int level) {
        if (level <= LogHandler::TRACE)         std::cout<<"TRACE";
        else if (level <= LogHandler::DEBUG)    std::cout<<"DEBUG";
        else if (level <= LogHandler::INFO)     std::cout<<"INFO";
        else if (level <= LogHandler::WARN)     std::cout<<"WARN";
        else if (level <= LogHandler::ERROR)    std::cout<<"ERROR";
        else std::cout<<"FATAL";
        std::cout<<" ";
    }

    virtual void log(bool value)        {std::cout<<value;}
    virtual void log(Byte value)        {std::cout<<value;}
    virtual void log(UByte value)       {std::cout<<value;}
    virtual void log(Short value)       {std::cout<<value;}
    virtual void log(UShort value)      {std::cout<<value;}
    virtual void log(Int value)         {std::cout<<value;}
    virtual void log(UInt value)        {std::cout<<value;}
    virtual void log(BigInt value)      {std::cout<<value;}
    virtual void log(float value)       {std::cout<<value;}
    virtual void log(double value)      {std::cout<<value;}
    virtual void log(IDValue value)     {std::cout<<value.str();}
    virtual void log(StringRef value)   {std::cout<<value;}
    virtual void log(const char* value) {std::cout<<value;}
    virtual void log(const void* value) {std::cout<<value;}

    virtual void end() {
        std::cout<<endl;
    }

    static void Init() {
        AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), LogHandler::MyType());
        type_ = type;
    }

    CUBEFS_DECLARE_REFLECTION;
};

template <typename Interface>
Type* DefaultLogHandlerImplT<Interface>::type_		= NULL;
typedef DefaultLogHandlerImplT<DefaultLogHandler>			DefaultLogHandlerImpl;



template <typename Interface>
class LoggerImplT: public TypedImplT<Interface> {
	typedef LoggerImplT<Interface> 	Me;
	typedef TypedImplT<Interface>	Base;
public:
    LoggerImplT(): Base(), level_(LogHandler::DEBUG), handler_(GetDefaultLogHandler()) {}

    virtual Int GetLogLevel() const {
        return level_;
    }

    virtual void SetLogLevel(Int level) {
        level_ = level;
    }

    virtual LogHandler* GetLogHandler() const {
        return handler_;
    }

    virtual void SetLogHandler(LogHandler* handler) {
        handler_ = handler;
    }

    virtual void begin(Int level)       {if (handler_ != NULL) handler_->begin(level);}
    virtual void end()                  {if (handler_ != NULL) handler_->end();}

    virtual void log(bool value)        {if (handler_ != NULL) handler_->log(value);}
    virtual void log(Byte value)        {if (handler_ != NULL) handler_->log(value);}
    virtual void log(UByte value)       {if (handler_ != NULL) handler_->log(value);}
    virtual void log(Short value)       {if (handler_ != NULL) handler_->log(value);}
    virtual void log(UShort value)      {if (handler_ != NULL) handler_->log(value);}
    virtual void log(Int value)         {if (handler_ != NULL) handler_->log(value);}
    virtual void log(UInt value)        {if (handler_ != NULL) handler_->log(value);}
    virtual void log(Long value)        {if (handler_ != NULL) handler_->log((BigInt)value);}
    virtual void log(BigInt value)      {if (handler_ != NULL) handler_->log(value);}
    virtual void log(float value)       {if (handler_ != NULL) handler_->log(value);}
    virtual void log(double value)      {if (handler_ != NULL) handler_->log(value);}
    virtual void log(IDValue value)     {if (handler_ != NULL) handler_->log(value);}
    virtual void log(StringRef value)   {if (handler_ != NULL) handler_->log(value);}
    virtual void log(const char* value) {if (handler_ != NULL) handler_->log(value);}
    virtual void log(const void* value) {if (handler_ != NULL) handler_->log(value);}

    virtual void log(size_t value)      {if (handler_ != NULL) handler_->log((BigInt)value);}


    static void Init()
    {
        AbstractType *type = new AbstractType(TypeNameFactory<Interface>::name(), Typed::MyType());
        type_ = type;

        type->AddOperation(new BasicOperation<Int (Logger::*)(), Int (Logger::*)() const>(type, "GetLogLevel", &Logger::GetLogLevel));
        type->AddOperation(new BasicOperation<void (Logger::*)(Int)>(type, "SetLogLevel", "level", &Logger::SetLogLevel));

        type->AddOperation(new BasicOperation<Typed* (Logger::*)(), LogHandler* (Logger::*)() const>(type, LogHandler::MyType(), "GetLogHandler", &Logger::GetLogHandler));
        type->AddOperation(new BasicOperation<void (Logger::*)(LogHandler*)>(type, "SetLogHandler", "handler", &Logger::SetLogHandler));
    }

    CUBEFS_DECLARE_REFLECTION;

private:

    Int         level_;
    LogHandler* handler_;
};

template <typename Interface>
Type* LoggerImplT<Interface>::type_		= NULL;
typedef LoggerImplT<Logger>				LoggerImpl;



class Locker {
	Logger& logger_;

public:
	Locker(Logger& logger, Int level): logger_(logger) {
		logger_.begin(level);
	}

	~Locker() throw() {
		try {
			logger_.end();
		}
		catch (...) {}
	}
};



template <typename T>
Logger& operator<<(Logger &log, const T& value) {
    log.log(value);
    return log;
}

template <typename T0>
bool log(Logger& log, Int level, const T0& v0) throw () {
    try {
        Locker lock(log, level);
        log<<v0;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <typename T0, typename T1>
bool log(Logger& log, Int level, const T0& v0, const T1& v1) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<v1;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <typename T0, typename T1, typename T2>
bool log(Logger& log, Int level, const T0& v0, const T1& v1, const T2& v2) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <typename T0, typename T1, typename T2, typename T3>
bool log(Logger& log, Int level, const T0& v0, const T1& v1, const T2& v2, const T3& v3) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <typename T0, typename T1, typename T2, typename T3, typename T4>
bool log(Logger& log, Int level, const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <typename T0, typename T1, typename T2, typename T3, typename T4, typename T5>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7
>
bool log(Logger& log, Int level,
         const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
         const T5& v5, const T6& v6, const T7& v7) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8
>
bool log(Logger& log, Int level,
         const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
         const T5& v5, const T6& v6, const T7& v7, const T8& v8) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8, typename T9
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8, typename T9,
        typename T10
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9,
        const T10& v10) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" ";
        log<<v10;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8, typename T9,
        typename T10, typename T11
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9,
        const T10& v10, const T11& v11) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" ";
        log<<v10<<" "<<v11;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8, typename T9,
        typename T10, typename T11, typename T12
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9,
        const T10& v10, const T11& v11, const T12& v12) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" ";
        log<<v10<<" "<<v11<<" "<<v12;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <
        typename T0, typename T1, typename T2, typename T3, typename T4,
        typename T5, typename T6, typename T7, typename T8, typename T9,
        typename T10, typename T11, typename T12, typename T13
>
bool log(Logger& log, Int level,
        const T0& v0, const T1& v1, const T2& v2, const T3& v3, const T4& v4,
        const T5& v5, const T6& v6, const T7& v7, const T8& v8, const T9& v9,
        const T10& v10, const T11& v11, const T12& v12, const T13& v13) throw () {
    try {
        Locker lock(log, level);
        log<<v0<<" "<<v1<<" "<<v2<<" "<<v3<<" "<<v4<<" "<<v5<<" "<<v6<<" "<<v7<<" "<<v8<<" "<<v9<<" ";
        log<<v10<<" "<<v11<<" "<<v12<<" "<<v13;
        return true;
    }
    catch (...) {
        return false;
    }
}

template <>
struct ParameterTypeHelper<LogHandler*> {
    static LogHandler* convert(Typed* value) {
        return static_cast<LogHandler*>(value);
    }
};



}}

#define CUBEFS_LOG(logger_, level, ...)                                         \
    if (logger_.is_log(level))                                                  \
        cubefs::api::log(logger_.logger(), level, CUBEFS_SOURCE, logger_.type_name(), __FUNCTION__, ##__VA_ARGS__)

#define CUBEFS_DEBUG(logger_, ...)                                              \
    CUBEFS_LOG(logger_, cubefs::api::LogHandler::DEBUG, ##__VA_ARGS__)

#define CUBEFS_WARN(logger_, ...)                                               \
    CUBEFS_LOG(logger_, cubefs::api::LogHandler::WARN, ##__VA_ARGS__)

#define CUBEFS_ERROR(logger_, ...)                                              \
    CUBEFS_LOG(logger_, cubefs::api::LogHandler::ERROR, ##__VA_ARGS__)

#define CUBEFS_INFO(logger_, ...)                                               \
    CUBEFS_LOG(logger_, cubefs::api::LogHandler::INFO, ##__VA_ARGS__)

#define CUBEFS_TRACE(logger_, ...)                                              \
    CUBEFS_LOG(logger_, cubefs::api::LogHandler::TRACE, ##__VA_ARGS__)

#endif
